#include "NetInterface.h"
#include <WinSock2.h>
#include <IPTypes.h>
#include <iphlpapi.h>


#pragma comment(lib, "iphlpapi.lib")
namespace jlh
{
	std::string NetInterface::GetLocalIPAddress()
	{
#ifdef _WIN32
		PIP_ADAPTER_INFO pIpAdapterInfo = new IP_ADAPTER_INFO();
		unsigned long size = sizeof(IP_ADAPTER_INFO);

		int ret = GetAdaptersInfo(pIpAdapterInfo, &size);
		if (ret == ERROR_BUFFER_OVERFLOW)
		{
			delete pIpAdapterInfo;
			pIpAdapterInfo = (PIP_ADAPTER_INFO)new BYTE[size];
			ret = GetAdaptersInfo(pIpAdapterInfo, &size);
		}

		if (ret != ERROR_SUCCESS)
		{
			delete pIpAdapterInfo;
			return "0.0.0.0";
		}

		while (pIpAdapterInfo)
		{
			IP_ADDR_STRING *pIpAddrString = &(pIpAdapterInfo->IpAddressList);
			while (pIpAddrString)
			{
				if (strcmp(pIpAddrString->IpAddress.String, "127.0.0.1") != 0
					&& strcmp(pIpAddrString->IpAddress.String, "0.0.0.0") != 0)
				{
					// pIpAddrString->IpMask.String 
					//pIpAdapterInfo->GatewayList.IpAddress.String
					std::string ip(pIpAddrString->IpAddress.String);
					//delete pIpAdapterInfo;
					return ip;
				}
				pIpAddrString = pIpAddrString->Next;
			} while (pIpAddrString);
			pIpAdapterInfo = pIpAdapterInfo->Next;
		}

		delete pIpAdapterInfo;
		return "0.0.0.0";
#endif // _WIN32

	}



	bool SocketUtil::Bind(SOCKET  sockfd, std::string ip, uint16_t port)
	{
		struct sockaddr_in addr = { 0 };
		addr.sin_family = AF_INET;
		addr.sin_addr.s_addr = inet_addr(ip.c_str());
		addr.sin_port = htons(port);
		if (SOCKET_ERROR == ::bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)))
		{
			return false;
		}

		return true;
	}
	void SocketUtil::SetNonBlock(SOCKET fd)
	{
#if defined(__linux) || defined(__linux__)
#else
		unsigned long on = 1;
		ioctlsocket(fd, FIONBIO, &on);
#endif
	}
	void SocketUtil::SetBlock(SOCKET fd, int writeTimeout)
	{
#if defined(__linux) || defined(__linux__)
#elif defined(WIN32) || defined(_WIN32)
		unsigned long on = 0;
		ioctlsocket(fd, FIONBIO, &on);
#endif
		if (0 < writeTimeout)
		{
#if defined(__linux) || defined(__linux__)
#elif defined(WIN32) || defined(_WIN32)
			unsigned long ms = (unsigned long)writeTimeout;
			setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&ms, sizeof(unsigned long));
#endif
		}
	}
	void SocketUtil::SetReuseAddr(SOCKET sockfd)
	{
		int on = 1;
		setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));
	}
	void SocketUtil::SetNoDelay(SOCKET sockfd)
	{
		int on = 1;
		setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char*)&on, sizeof(on));
	}
	void SocketUtil::SetKeepAlive(SOCKET sockfd)
	{
		int on = 1;
		setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (char*)&on, sizeof(on));
	}
	void SocketUtil::SetSendBufSize(SOCKET sockfd, int size)
	{
		setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char*)&size, sizeof(size));
	}
	void SocketUtil::SetRecvBufSize(SOCKET sockfd, int size)
	{
		setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (char*)&size, sizeof(size));
	}
	void SocketUtil::Close(SOCKET sockfd)
	{
#if defined(__linux) || defined(__linux__)
#elif defined(WIN32) || defined(_WIN32)
		::closesocket(sockfd);
#endif
	}
}
